<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="generator" content="Docusaurus v2.0.0-alpha.65">
<title data-react-helmet="true">9.27 分表分库 | Fur</title><meta data-react-helmet="true" name="docsearch:version" content="current,latest"><meta data-react-helmet="true" name="twitter:card" content="summary_large_image"><meta data-react-helmet="true" property="og:title" content="9.27 分表分库 | Fur"><meta data-react-helmet="true" name="description" content="本章 9.27.2 至 9.27.5 小节挪用博主：雨点的名字 的 分库分表 - 理论 博客内容。特此声明。"><meta data-react-helmet="true" property="og:description" content="本章 9.27.2 至 9.27.5 小节挪用博主：雨点的名字 的 分库分表 - 理论 博客内容。特此声明。"><meta data-react-helmet="true" property="og:url" content="https://chinadot.net/docs/split-db"><link data-react-helmet="true" rel="shortcut icon" href="/img/favicon.ico"><link data-react-helmet="true" rel="canonical" href="https://chinadot.net/docs/split-db"><link rel="stylesheet" href="/styles.8aef5b7b.css">
<link rel="preload" href="/styles.1af3f57f.js" as="script">
<link rel="preload" href="/runtime~main.e2f14afc.js" as="script">
<link rel="preload" href="/main.cb4b4173.js" as="script">
<link rel="preload" href="/1.7bcff63a.js" as="script">
<link rel="preload" href="/2.f71a81b4.js" as="script">
<link rel="preload" href="/01a85c17.755a5885.js" as="script">
<link rel="preload" href="/1be78505.572787d1.js" as="script">
<link rel="preload" href="/6875c492.a75dca0e.js" as="script">
<link rel="preload" href="/a6aa9e1f.005e050b.js" as="script">
<link rel="preload" href="/ccc49370.0b963bc5.js" as="script">
<link rel="preload" href="/ece76bd1.5f0e74a1.js" as="script">
<link rel="preload" href="/86.763e07e0.js" as="script">
<link rel="preload" href="/85.f9b1e033.js" as="script">
<link rel="preload" href="/f976f453.d1d87a8b.js" as="script">
<link rel="preload" href="/17896441.b0924391.js" as="script">
<link rel="preload" href="/03ebb857.1318b1fe.js" as="script">
</head>
<body>
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script><div id="__docusaurus">
<nav class="navbar navbar--fixed-top"><div class="navbar__inner"><div class="navbar__items"><div aria-label="Navigation bar toggle" class="navbar__toggle" role="button" tabindex="0"><svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30" role="img" focusable="false"><title>Menu</title><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></div><a class="navbar__brand" href="/"><img class="navbar__logo" src="/img/logo.png" alt="Fur Logo"><strong class="navbar__title">Fur</strong></a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/docs/">Next</a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/docs">文档</a><a class="navbar__item navbar__link" href="/blog">博客</a><a target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">配置</a></div><div class="navbar__items navbar__items--right"><a target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">视频</a><div class="navbar__item dropdown dropdown--hoverable dropdown--right"><a target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">工具</a><ul class="dropdown__menu"><li><a target="_blank" rel="noopener noreferrer" class="dropdown__link" position="left">代码生成器</a></li></ul></div><a href="https://gitee.com/monksoul/Fur/board" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">看板</a><div class="navbar__item dropdown dropdown--hoverable dropdown--right"><a target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">仓库</a><ul class="dropdown__menu"><li><a href="https://gitee.com/monksoul/Fur" target="_blank" rel="noopener noreferrer" class="dropdown__link" position="left">Gitee</a></li><li><a href="https://github.com/MonkSoul/Fur" target="_blank" rel="noopener noreferrer" class="dropdown__link" position="left">GitHub</a></li></ul></div><div class="react-toggle react-toggle--disabled displayOnlyInLargeViewport_2aTZ"><div class="react-toggle-track"><div class="react-toggle-track-check"><span class="toggle_BsTx">🌜</span></div><div class="react-toggle-track-x"><span class="toggle_BsTx">🌞</span></div></div><div class="react-toggle-thumb"></div><input type="checkbox" disabled="" aria-label="Dark mode toggle" class="react-toggle-screenreader-only"></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div><div class="navbar-sidebar"><div class="navbar-sidebar__brand"><a class="navbar__brand" href="/"><img class="navbar__logo" src="/img/logo.png" alt="Fur Logo"><strong class="navbar__title">Fur</strong></a></div><div class="navbar-sidebar__items"><div class="menu"><ul class="menu__list"><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link">Versions</a></li><li class="menu__list-item"><a aria-current="page" class="menu__link navbar__link--active" href="/docs">文档</a></li><li class="menu__list-item"><a class="menu__link" href="/blog">博客</a></li><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link">配置</a></li><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link">视频</a></li><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link menu__link--sublist">工具</a><ul class="menu__list"><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link" position="left">代码生成器</a></li></ul></li><li class="menu__list-item"><a href="https://gitee.com/monksoul/Fur/board" target="_blank" rel="noopener noreferrer" class="menu__link">看板</a></li><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link menu__link--sublist">仓库</a><ul class="menu__list"><li class="menu__list-item"><a href="https://gitee.com/monksoul/Fur" target="_blank" rel="noopener noreferrer" class="menu__link" position="left">Gitee</a></li><li class="menu__list-item"><a href="https://github.com/MonkSoul/Fur" target="_blank" rel="noopener noreferrer" class="menu__link" position="left">GitHub</a></li></ul></li></ul></div></div></div></nav><div class="main-wrapper"><div class="docPage_2gpo"><div class="docSidebarContainer_3_JD" role="complementary"><div class="sidebar_2urC"><div class="menu menu--responsive menu_5FrY"><button aria-label="Open Menu" aria-haspopup="true" class="button button--secondary button--sm menu__button" type="button"><svg aria-label="Menu" class="sidebarMenuIcon_Dm3K" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 32 32" role="img" focusable="false"><title>Menu</title><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><ul class="menu__list"><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">1. 框架介绍</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/">1.1 介绍</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/author">1.2 关于作者</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/source">1.3 源码结构</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/reference">1.4 项目引用</a></li></ul></li><li class="menu__list-item"><a class="menu__link" href="/docs/get-start">2. 一分钟入门</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/appstartup">3. 应用启动</a></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">4. 配置与选项</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/configuration">4.1 配置</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/options">4.2 选项</a></li></ul></li><li class="menu__list-item"><a class="menu__link" href="/docs/dynamic-api-controller">5. 动态 WebAPI</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/specification-document">6. 规范化接口文档</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/friendly-exception">7. 友好异常处理</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/data-validation">8. 数据校验</a></li><li class="menu__list-item"><a class="menu__link menu__link--sublist menu__link--active" href="#!">9. 数据库操作指南</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext">9.1 数据库上下文</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-locator">9.2 数据库上下文定位器</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/entity">9.3 数据库实体</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-repository">9.4 仓储模式</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-add">9.5 新增操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-update">9.6 更新操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-add-or-update">9.7 新增或更新操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-delete">9.8 删除操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-batch">9.9 批量操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-query">9.10 查询操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-hight-query">9.11 高级查询操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-view">9.12 视图操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-proc">9.13 存储过程操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-function">9.14 函数操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-sql">9.15 Sql 操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-sql-template">9.16 Sql 模板</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-sql-proxy">9.17 Sql 高级代理</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-multi-database">9.18 多数据库操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-db-first">9.19 数据库生成模型</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-code-first">9.20 模型生成数据库</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-seed-data">9.21 实体种子数据</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-audit">9.22 审计日志</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-filter">9.23 实体/全局查询筛选器</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-Interceptor">9.24 数据库操作拦截器</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/tran">9.25 事务和工作单元</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/dbcontext-read-write">9.26 读写分离/主从复制</a></li><li class="menu__list-item"><a aria-current="page" class="menu__link menu__link--active active" tabindex="0" href="/docs/split-db">9.27 分表分库</a></li></ul></li><li class="menu__list-item"><a class="menu__link" href="/docs/saas">10. SaaS 多租户</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/dependency-injection">11. 依赖注入/控制反转</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/object-mapper">12. 对象数据映射</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/cache">13. 分布式缓存</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/auth-control">14. 安全鉴权</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/cors">15. CORS 跨域</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/local-language">16. 多语言处理</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/view-engine">17. 视图引擎</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/event-bus">18. 事件总线</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/logging">19. 日志记录</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/http">20. 网络请求</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/process-service">21. 进程服务</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/job">22. 任务调度</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/signalr">23. 即时通讯</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/grpc">24. Grpc 服务</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/deploy">25. 托管部署</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/devops">26. 持续部署集成</a></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">27. 测试指南</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/unittest">27.1 单元测试</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/performance">27.2 性能测试</a></li></ul></li><li class="menu__list-item"><a class="menu__link" href="/docs/contribute">28. 贡献指南</a></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">29. 常见问题</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/answer">29.1 常见问题</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/errors">29.2 常见错误</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/gooduse">29.3 最佳实践</a></li></ul></li></ul></div></div></div><main class="docMainContainer_3EyW"><div class="container padding-vert--lg docItemWrapper_1EkI"><div class="row"><div class="col docItemCol_2ASc"><div class="docItemContainer_3QWW"><article><header><h1 class="docTitle_1Lrw">9.27 分表分库</h1></header><div class="markdown"><div class="admonition admonition-important alert alert--info"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>特此声明</h5></div><div class="admonition-content"><p>本章 <code>9.27.2</code> 至 <code>9.27.5</code> 小节挪用博主：<a href="https://www.cnblogs.com/qdhxhz/" target="_blank" rel="noopener noreferrer">雨点的名字</a> 的 <a href="https://www.cnblogs.com/qdhxhz/p/11608222.html" target="_blank" rel="noopener noreferrer">分库分表 - 理论</a> 博客内容。<strong>特此声明。</strong></p></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="9271-应用场景"></a>9.27.1 应用场景<a aria-hidden="true" tabindex="-1" class="hash-link" href="#9271-应用场景" title="Direct link to heading">#</a></h2><p>数据库中的数据量不一定是可控的，在未进行分库分表的情况下，随着时间和业务的发展，库中的表会越来越多，表中的数据量也会越来越大，相应地，数据操作增删改查的开销也会越来越大。</p><p>另外，由于无法进行分布式式部署，而一台服务器的资源（CPU、磁盘、内存、IO 等）是有限的，最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。</p><p>这个时候就需要对数据库或数据表进行拆分。</p><p>数据切分可以分为：<code>垂直切分</code> 和 <code>水平切分</code>。</p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="9272-垂直切分"></a>9.27.2 垂直切分<a aria-hidden="true" tabindex="-1" class="hash-link" href="#9272-垂直切分" title="Direct link to heading">#</a></h2><p>垂直切分又可以分为: 垂直分库和垂直分表。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="92721-垂直分库"></a>9.27.2.1 垂直分库<a aria-hidden="true" tabindex="-1" class="hash-link" href="#92721-垂直分库" title="Direct link to heading">#</a></h3><p>根据业务耦合性，将关联度低的不同表存储在不同的数据库。做法与大系统拆分为多个小系统类似，按业务分类进行独立划分。与&quot;微服务治理&quot;的做法相似，每个微服务使用单独的一个数据库。</p><img src="/img/dbsplit1.jpg"><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>说明</h5></div><div class="admonition-content"><p>一开始我们是单体服务，所以只有一个数据库，所有的表都在这个库里。</p><p>后来因为业务需求,单体服务变成微服务治理。所以将之前的一个商品库，拆分成多个数据库。每个微服务对于一个数据库。</p></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="92722-垂直分表"></a>9.27.2.2 垂直分表<a aria-hidden="true" tabindex="-1" class="hash-link" href="#92722-垂直分表" title="Direct link to heading">#</a></h3><p>把一个表的多个字段分别拆成多个表，一般按字段的冷热拆分，热字段一个表，冷字段一个表。从而提升了数据库性能。</p><img src="/img/dbsplit2.jpg"><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>说明</h5></div><div class="admonition-content"><p>一开始商品表中包含商品的所有字段，但是我们发现:</p><p>1.商品详情和商品属性字段较长。2.商品列表的时候我们是不需要显示商品详情和商品属性信息，只有在点进商品商品的时候才会展示商品详情信息。</p><p>所以可以考虑把商品详情和商品属性单独切分一张表，提高查询效率。</p></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="92723-优缺点"></a>9.27.2.3 优缺点<a aria-hidden="true" tabindex="-1" class="hash-link" href="#92723-优缺点" title="Direct link to heading">#</a></h3><ul><li><p>优点</p><ul><li>解决业务系统层面的耦合，业务清晰</li><li>与微服务的治理类似，也能对不同业务的数据进行分级管理、维护、监控、扩展等</li><li>高并发场景下，垂直切分一定程度的提升 IO、数据库连接数、单机硬件资源的瓶颈</li></ul></li><li><p>缺点</p><ul><li>分库后无法 Join，只能通过接口聚合方式解决，提升了开发的复杂度</li><li>分库后分布式事务处理复杂</li><li>依然存在单表数据量过大的问题（需要水平切分）</li></ul></li></ul><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="9273-水平切分"></a>9.27.3 水平切分<a aria-hidden="true" tabindex="-1" class="hash-link" href="#9273-水平切分" title="Direct link to heading">#</a></h2><p>当一个应用难以再细粒度的垂直切分或切分后数据量行数巨大，存在单库读写、存储性能瓶颈，这时候就需要进行水平切分了。</p><p>水平切分也可以分为：水平分库和水平分表。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="92731-水平分库"></a>9.27.3.1 水平分库<a aria-hidden="true" tabindex="-1" class="hash-link" href="#92731-水平分库" title="Direct link to heading">#</a></h3><p>上面虽然已经把商品库分成 3 个库，但是随着业务的增加一个订单库也出现 QPS 过高，数据库响应速度来不及，一般 mysql 单机也就 1000 左右的 QPS，如果超过 1000 就要考虑分库。</p><img src="/img/dbsplit3.jpg"><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="92732-水平分表"></a>9.27.3.2 水平分表<a aria-hidden="true" tabindex="-1" class="hash-link" href="#92732-水平分表" title="Direct link to heading">#</a></h3><p>一般我们一张表的数据不要超过 1 千万,如果表数据超过 1 千万，并且还在不断增加数据，那就可以考虑分表。</p><img src="/img/dbsplit4.jpg"><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="92733-优缺点"></a>9.27.3.3 优缺点<a aria-hidden="true" tabindex="-1" class="hash-link" href="#92733-优缺点" title="Direct link to heading">#</a></h3><ul><li><p>优点</p><ul><li>不存在单库数据量过大、高并发的性能瓶颈，提升系统稳定性和负载能力</li><li>应用端改造较小，不需要拆分业务模块</li></ul></li><li><p>缺点</p><ul><li>跨分片的事务一致性难以保证</li><li>跨库的 Join 关联查询性能较差</li><li>数据多次扩展难度和维护量极大</li></ul></li></ul><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="9274-数据分片规则"></a>9.27.4 数据分片规则<a aria-hidden="true" tabindex="-1" class="hash-link" href="#9274-数据分片规则" title="Direct link to heading">#</a></h2><p>我们考虑去水平切分表，将一张表水平切分成多张表，这就涉及到数据分片的规则，比较常见的有：Hash 取模分表、数值 Range 分表、一致性 Hash 算法分表。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="92741-hash-取模分表"></a>9.27.4.1 Hash 取模分表<a aria-hidden="true" tabindex="-1" class="hash-link" href="#92741-hash-取模分表" title="Direct link to heading">#</a></h3><p>一般采用 Hash 取模的切分方式，例如：假设按 goods_id 分 4 张表。（goods_id%4 取整确定表）</p><img src="/img/dbsplit5.jpg"><p><strong>优缺点</strong></p><ul><li><p>优点</p><ul><li>数据分片相对比较均匀，不容易出现热点和并发访问的瓶颈。</li></ul></li><li><p>缺点</p><ul><li>后期分片集群扩容时，需要迁移旧的数据很难。</li><li>容易面临跨分片查询的复杂问题。比如上例中，如果频繁用到的查询条件中不带 goods_id 时，将会导致无法定位数据库，从而需要同时向 4 个库发起查询，
再在内存中合并数据，取最小集返回给应用，分库反而成为拖累。</li></ul></li></ul><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="92742-数值-range-分表"></a>9.27.4.2 数值 Range 分表<a aria-hidden="true" tabindex="-1" class="hash-link" href="#92742-数值-range-分表" title="Direct link to heading">#</a></h3><p>按照时间区间或 ID 区间来切分。例如：将 goods_id 为 1-1000 的记录分到第一个表，1000-2000 的分到第二个表，以此类推。</p><img src="/img/dbsplit6.jpg"><p><strong>优缺点</strong></p><ul><li><p>优点</p><ul><li>单表大小可控</li><li>天然便于水平扩展，后期如果想对整个分片集群扩容时，只需要添加节点即可，无需对其他分片的数据进行迁移</li><li>使用分片字段进行范围查找时，连续分片可快速定位分片进行快速查询，有效避免跨分片查询的问题。</li></ul></li><li><p>缺点</p><ul><li>热点数据成为性能瓶颈。
例如按时间字段分片，有些分片存储最近时间段内的数据，可能会被频繁的读写，而有些分片存储的历史数据，则很少被查询</li></ul></li></ul><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="92743-一致性-hash-算法"></a>9.27.4.3 一致性 Hash 算法<a aria-hidden="true" tabindex="-1" class="hash-link" href="#92743-一致性-hash-算法" title="Direct link to heading">#</a></h3><p>一致性 Hash 算法能很好的解决因为 Hash 取模而产生的分片集群扩容时，需要迁移旧的数据的难题。具体原理可参考 <a href="https://www.cnblogs.com/duhuo/p/4996105.html" target="_blank" rel="noopener noreferrer">https://www.cnblogs.com/duhuo/p/4996105.html</a></p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="9275-分库分表带来的问题"></a>9.27.5 分库分表带来的问题<a aria-hidden="true" tabindex="-1" class="hash-link" href="#9275-分库分表带来的问题" title="Direct link to heading">#</a></h2><p>任何事情都有两面性，分库分表也不例外，如果采用分库分表，会引入新的的问题：</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="92751-分布式事务问题"></a>9.27.5.1 分布式事务问题<a aria-hidden="true" tabindex="-1" class="hash-link" href="#92751-分布式事务问题" title="Direct link to heading">#</a></h3><p>使用分布式事务中间件解决，具体是通过最终一致性还是强一致性分布式事务，看业务需求，这里就不多说。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="92752-跨节点关联查询-join-问题"></a>9.27.5.2 跨节点关联查询 Join 问题<a aria-hidden="true" tabindex="-1" class="hash-link" href="#92752-跨节点关联查询-join-问题" title="Direct link to heading">#</a></h3><p>切分之前，我们可以通过 Join 来完成。而切分之后，数据可能分布在不同的节点上，此时 Join 带来的问题就比较麻烦了，考虑到性能，尽量避免使用 Join 查询。</p><p>解决这个问题的一些方法：</p><ul><li><strong>全局表</strong></li></ul><p>全局表，也可看做是 &quot;数据字典表&quot;，就是系统中所有模块都可能依赖的一些表，为了避免跨库 Join 查询，可以将 这类表在每个数据库中都保存一份。这些数据通常</p><p>很少会进行修改，所以也不担心一致性的问题。</p><ul><li><strong>字段冗余</strong></li></ul><p>利用空间换时间，为了性能而避免 join 查询。例：订单表保存 userId 时候,也将 userName 冗余保存一份，这样查询订单详情时就不需要再去查询&quot;买家 user 表&quot;了。</p><ul><li><strong>数据组装</strong></li></ul><p>在系统层面，分两次查询。第一次查询的结果集中找出关联数据 id，然后根据 id 发起第二次请求得到关联数据。最后将获得到的数据进行字段拼装。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="92753-跨节点分页、排序、函数问题"></a>9.27.5.3 跨节点分页、排序、函数问题<a aria-hidden="true" tabindex="-1" class="hash-link" href="#92753-跨节点分页、排序、函数问题" title="Direct link to heading">#</a></h3><p>跨节点多库进行查询时，会出现 Limit 分页、Order by 排序等问题。分页需要按照指定字段进行排序，当排序字段就是分片字段时，通过分片规则就比较容易定位到指定的分片；</p><p>当排序字段非分片字段时，就变得比较复杂了。需要先在不同的分片节点中将数据进行排序并返回，然后将不同分片返回的结果集进行汇总和再次排序，最终返回给用户。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="92754-全局主键避重问题"></a>9.27.5.4 全局主键避重问题<a aria-hidden="true" tabindex="-1" class="hash-link" href="#92754-全局主键避重问题" title="Direct link to heading">#</a></h3><p>如果都用主键自增肯定不合理，如果用 UUID 那么无法做到根据主键排序，所以我们可以考虑通过<a href="https://www.cnblogs.com/qdhxhz/p/11372658.html" target="_blank" rel="noopener noreferrer">雪花 ID</a> 来作为数据库的主键，</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="92755-数据迁移问题"></a>9.27.5.5 数据迁移问题<a aria-hidden="true" tabindex="-1" class="hash-link" href="#92755-数据迁移问题" title="Direct link to heading">#</a></h3><p>采用双写的方式，修改代码，所有涉及到分库分表的表的增、删、改的代码，都要对新库进行增删改。同时，再有一个数据抽取服务，不断地从老库抽数据，往新库写，</p><p>边写边按时间比较数据是不是最新的。</p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="9276-如何实现"></a>9.27.6 如何实现<a aria-hidden="true" tabindex="-1" class="hash-link" href="#9276-如何实现" title="Direct link to heading">#</a></h2><div class="admonition admonition-caution alert alert--warning"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>特别说明</h5></div><div class="admonition-content"><p>由于分表分库不仅仅需要内置代码的支持，同时还需要集成数据库中间件，这里推荐 <code>MyCat</code> 中间件。<a href="http://www.mycat.org.cn/" target="_blank" rel="noopener noreferrer">MyCat 官方网站</a></p></div></div><p><code>Fur</code> 框架中提供了轻量级的 <code>分表分库</code> 支持：</p><ul><li><strong>动态切换数据库</strong></li></ul><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">// 直接改变数据库</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">repository.ChangeDatabase(&quot;数据库连接字符串&quot;);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">// 通过数据库上下文定位器切换</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">repository.Change&lt;Entity, MyDbContextLocator2&gt;();</span></div></div></div></div></div><p>如需跨库查询，需用到数据库技术，如 <code>SqlServer</code> 链接服务器或同义词。</p><ul><li><strong>动态切换数据库表</strong></li></ul><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">// 直接改变表，会有多线程操作bug，同时无法刷新模型</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">repository.ChangeTable(&quot;数据库表&quot;);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">// 创建新的 DbContext，然后刷新 OnModelCreating（推荐方式）</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">var dynamicDbContextResolve = App.TransientServices.GetService&lt;Func&lt;Type, IScoped, DbContext&gt;&gt;();</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">var dynamicDbContext = dynamicDbContextResolve(typeof(MyDbContextLocator), default);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">// 重新调用 OnModelCreating，在 OnModelCreating 中配置 ToTable(&quot;动态表&quot;) 即可。</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">DynamicModelCacheKeyFactory.RebuildModels();</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">var persons= dynamicDbContext.Set&lt;Person&gt;();</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">persons.Add(new Person{});</span></div></div></div></div></div><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>了解更多</h5></div><div class="admonition-content"><p>想了解更多 <code>DynamicModelCacheKeyFactory</code> 知识可查阅 <a href="https://docs.microsoft.com/zh-cn/ef/core/modeling/dynamic-model" target="_blank" rel="noopener noreferrer">EF Core - 多个模型之间交替</a> 章节。</p></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="9277-反馈与建议"></a>9.27.7 反馈与建议<a aria-hidden="true" tabindex="-1" class="hash-link" href="#9277-反馈与建议" title="Direct link to heading">#</a></h2><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>与我们交流</h5></div><div class="admonition-content"><p>给 Fur 提 <a href="https://gitee.com/monksoul/Fur/issues/new?issue" target="_blank" rel="noopener noreferrer">Issue</a>。</p></div></div></div></article><div class="margin-vert--xl"><div class="row"><div class="col"><a href="https://gitee.com/monksoul/Fur/tree/main/handbook/docs/split-db.mdx" target="_blank" rel="noreferrer noopener"><svg fill="currentColor" height="1.2em" width="1.2em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 40 40" style="margin-right:0.3em;vertical-align:sub"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div></div></div><div class="margin-vert--lg"><nav class="pagination-nav" aria-label="Blog list page navigation"><div class="pagination-nav__item"><a class="pagination-nav__link" href="/docs/dbcontext-read-write"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">« 9.26 读写分离/主从复制</div></a></div><div class="pagination-nav__item pagination-nav__item--next"><a class="pagination-nav__link" href="/docs/saas"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">10. SaaS 多租户 »</div></a></div></nav></div></div></div><div class="col col--3"><div class="tableOfContents_3SO_"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#9271-应用场景" class="table-of-contents__link">9.27.1 应用场景</a></li><li><a href="#9272-垂直切分" class="table-of-contents__link">9.27.2 垂直切分</a><ul><li><a href="#92721-垂直分库" class="table-of-contents__link">9.27.2.1 垂直分库</a></li><li><a href="#92722-垂直分表" class="table-of-contents__link">9.27.2.2 垂直分表</a></li><li><a href="#92723-优缺点" class="table-of-contents__link">9.27.2.3 优缺点</a></li></ul></li><li><a href="#9273-水平切分" class="table-of-contents__link">9.27.3 水平切分</a><ul><li><a href="#92731-水平分库" class="table-of-contents__link">9.27.3.1 水平分库</a></li><li><a href="#92732-水平分表" class="table-of-contents__link">9.27.3.2 水平分表</a></li><li><a href="#92733-优缺点" class="table-of-contents__link">9.27.3.3 优缺点</a></li></ul></li><li><a href="#9274-数据分片规则" class="table-of-contents__link">9.27.4 数据分片规则</a><ul><li><a href="#92741-hash-取模分表" class="table-of-contents__link">9.27.4.1 Hash 取模分表</a></li><li><a href="#92742-数值-range-分表" class="table-of-contents__link">9.27.4.2 数值 Range 分表</a></li><li><a href="#92743-一致性-hash-算法" class="table-of-contents__link">9.27.4.3 一致性 Hash 算法</a></li></ul></li><li><a href="#9275-分库分表带来的问题" class="table-of-contents__link">9.27.5 分库分表带来的问题</a><ul><li><a href="#92751-分布式事务问题" class="table-of-contents__link">9.27.5.1 分布式事务问题</a></li><li><a href="#92752-跨节点关联查询-join-问题" class="table-of-contents__link">9.27.5.2 跨节点关联查询 Join 问题</a></li><li><a href="#92753-跨节点分页、排序、函数问题" class="table-of-contents__link">9.27.5.3 跨节点分页、排序、函数问题</a></li><li><a href="#92754-全局主键避重问题" class="table-of-contents__link">9.27.5.4 全局主键避重问题</a></li><li><a href="#92755-数据迁移问题" class="table-of-contents__link">9.27.5.5 数据迁移问题</a></li></ul></li><li><a href="#9276-如何实现" class="table-of-contents__link">9.27.6 如何实现</a></li><li><a href="#9277-反馈与建议" class="table-of-contents__link">9.27.7 反馈与建议</a></li></ul></div></div></div></div></main></div></div><footer class="footer footer--dark"><div class="container"><div class="row footer__links"><div class="col footer__col"><h4 class="footer__title">文档</h4><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/docs">入门</a></li><li class="footer__item"><a class="footer__link-item" href="/docs">指南</a></li></ul></div><div class="col footer__col"><h4 class="footer__title">社区</h4><ul class="footer__items"><li class="footer__item"><a href="https://gitee.com/monksoul/Fur/issues" target="_blank" rel="noopener noreferrer" class="footer__link-item">讨论</a></li><li class="footer__item"><a href="https://gitee.com/monksoul/Fur/board" target="_blank" rel="noopener noreferrer" class="footer__link-item">看板</a></li></ul></div><div class="col footer__col"><h4 class="footer__title">更多</h4><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/blog">博客</a></li><li class="footer__item"><a href="https://gitee.com/monksoul/Fur" target="_blank" rel="noopener noreferrer" class="footer__link-item">仓库</a></li></ul></div></div><div class="text--center"><div>Copyright © 2020 Fur, Baiqian Co.,Ltd.</div></div></div></footer></div>
<script src="/styles.1af3f57f.js"></script>
<script src="/runtime~main.e2f14afc.js"></script>
<script src="/main.cb4b4173.js"></script>
<script src="/1.7bcff63a.js"></script>
<script src="/2.f71a81b4.js"></script>
<script src="/01a85c17.755a5885.js"></script>
<script src="/1be78505.572787d1.js"></script>
<script src="/6875c492.a75dca0e.js"></script>
<script src="/a6aa9e1f.005e050b.js"></script>
<script src="/ccc49370.0b963bc5.js"></script>
<script src="/ece76bd1.5f0e74a1.js"></script>
<script src="/86.763e07e0.js"></script>
<script src="/85.f9b1e033.js"></script>
<script src="/f976f453.d1d87a8b.js"></script>
<script src="/17896441.b0924391.js"></script>
<script src="/03ebb857.1318b1fe.js"></script>
</body>
</html>